#%%
import  os, time, random, wave, argparse, pygame

import numpy as np

from collections import deque
import matplotlib.pyplot as plt


g_show_plot = False

# 音符的频率字典？
pm_notes = {'C4':262, 'Eb':311, 'F':349, 'G':391, 'Bb':466}

def write_wave(f_name, data):
    '''
    写入wav文件
    '''
    file = wave.open(f_name, 'wr')

    n_channel = 1
    sample_wid = 2
    frame_rate = 44100
    # ?
    n_frame = 44100

    file.setparams((n_channel, sample_wid, frame_rate, n_frame, 'NONE', 'noncompressed'))
    file.writeframes(data)
    file.close()



def gener_note(freq):
    '''
    生成音符
    '''
    n_samples = 44100
    sample_rate = 44100
    n = int(sample_rate / freq)
    
    # 什么意思
    buf = deque([random.random()-0.5 for i in range(n)])
    if g_show_plot:
        ax, = plt.plot(buf)

    samples = np.array([0]*n_samples, 'float32')
    for i in range(n_samples):
        samples[i] = buf[0]
        avg = .995*.5*(buf[0]+buf[1])
        buf.append(avg)
        buf.popleft()
        if g_show_plot:
            if i % 1000 == 0:
                ax.set_ydata(buf)
                plt.draw()

    samples = np.array(samples*32767, 'int16')
    return samples.tostring()
            

class Note_player:
    def __init__(self):
        #？
        pygame.mixer.pre_init(44100, -16, 1, 2048)
        pygame.init()
        # 音符字典
        self.notes = {}


    def add(self, f_name):
        self.notes[f_name] = pygame.mixer.Sound(f_name)




    def play(self, f_name):
        try:
            # self.notes[f_name]是什么对象？
            self.notes[f_name].play()
        except:
            print(f'{f_name}不存在！')



    def play_rand(self):
        index = random.randint(0, len(self.notes)-1)
        # 什么意思？
        note = list(self.notes.value())[index]
        note.play()
        



def main():
    global g_plot

    parser = argparse.ArgumentParser(description='使用Karplus算法生成音乐')

    # store_true是什么意思？
    parser.add_argument('--display', action='store_true', required=False)
    parser.add_argument('--play', action='store_true', required=False)
    parser.add_argument('--piano', action='store_true', required=False)
    args = parser.parse_args()

    # 输入参数display？
    if args.display:
        g_plot = True
        # ?
        plt.ion()

    n_player = Note_player()


    print('正在生成音符……')
    for name, freq in list(pm_notes.items()):
        f_name = name + '.wav'
        if not os.path.exists(f_name) or args.display:
            data = gener_note(freq)
            print(f'正在生成{f_name}……')
            write_wave(f_name, data)
        else:
            print(f'{f_name}已存在，跳过……')


        n_player.add(name + '.wav')

        if args.display:
            n_player.play(name + '.wav')
            time.sleep(0.5)


    if args.play:
        while True:
            try:
                n_player.play_rand()
                rest = np.random.choice([1, 2, 4, 8], 1, p=[.15, .7, .1, .05])
                time.sleep(.25*rest[0])
            except KeyboardInterrupt:
                exit()


    if args.piano:
        while True:
            for event in pygame.event.get():
                if event.type == pygame.KEYUP:
                    print('按键按下')
                    n_player.play_rand()
                    time.sleep(0.5)
                        
if __name__ == '__main__':
    main()
